package device

import (
	"context"
	"fmt"
	"git.skcks.cn/Shikong/go-gb28181/pkg/config"
	"git.skcks.cn/Shikong/go-gb28181/pkg/log"
	"github.com/emiago/sipgo"
	"github.com/emiago/sipgo/sip"
	"github.com/icholy/digest"
	"time"
)

var registerSenders = make(map[string]*time.Ticker)

func StopAllRegister() {
	for _, timer := range registerSenders {
		timer.Stop()
	}
}

func SetupRegister(client *sipgo.Client, clientConfig *config.ClientConfig) {
	timer := time.NewTicker(time.Second * 3600)
	registerSenders[clientConfig.DeviceId] = timer
	go func() {
		for range timer.C {
			Register(client, clientConfig)
		}
	}()
	Register(client, clientConfig)
}

func Register(client *sipgo.Client, clientConfig *config.ClientConfig) {
	target := sip.Uri{
		User:    clientConfig.ServerId,
		Host:    clientConfig.ServerIp,
		Port:    clientConfig.ServerPort,
		Headers: sip.NewParams(),
	}
	uri := sip.Uri{User: clientConfig.DeviceId, Host: clientConfig.ListenIp, Port: clientConfig.ServerPort}
	req := sip.NewRequest(sip.REGISTER, target)
	req.AppendHeader(sip.NewHeader("X-GB-Ver", "2.0"))
	req.AppendHeader(sip.NewHeader("Contact", uri.String()))
	req.AppendHeader(sip.NewHeader("Expires", "3600"))

	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
	defer cancel()

	tx, err := client.TransactionRequest(ctx, req)
	defer tx.Terminate()
	if err != nil {
		log.Log().Error().Msgf("%v", err)
		return
	}

	resp, err := getResponse(tx)
	if err != nil {
		log.Log().Error().Msgf("%v", err)
		return
	}

	headers := resp.Headers()
	for _, h := range headers {
		log.Log().Info().Msgf("%v => %v", h.Name(), h.Value())
	}
	log.Log().Info().Msgf(resp.String())

	// 如果状态码是401，则需要验证
	if resp.StatusCode == 401 {
		wwwAuth := resp.GetHeader("WWW-Authenticate")
		chal, err := digest.ParseChallenge(wwwAuth.Value())
		if err != nil {
			log.Log().Error().Msgf("Fail to parse challenge %v", err)
			return
		}

		// Reply with digest
		cred, _ := digest.Digest(chal, digest.Options{
			Method:   req.Method.String(),
			Username: clientConfig.ServerId,
			URI:      target.String(),
			Password: clientConfig.Password,
		})

		newReq := req.Clone()
		newReq.RemoveHeader("Via") // Must be regenerated by tranport layer
		newReq.AppendHeader(sip.NewHeader("Authorization", cred.String()))

		ctx := context.Background()
		tx, err := client.TransactionRequest(ctx, newReq, sipgo.ClientRequestAddVia)
		if err != nil {
			log.Log().Error().Msgf("Fail to create transaction")
			return
		}

		resp, err = getResponse(tx)
		defer tx.Terminate()
		if err != nil {
			log.Log().Error().Msgf("Fail to get response")
			return
		}

		if resp.StatusCode != 403 {
			log.Log().Info().Msgf("设备:%s 注册成功", clientConfig.DeviceId)
		} else {
			log.Log().Error().Msgf("设备:%s 注册失败", clientConfig.DeviceId)
		}

		log.Log().Info().Msgf(resp.String())
	}
}

func getResponse(tx sip.ClientTransaction) (*sip.Response, error) {
	select {
	case <-tx.Done():
		return nil, fmt.Errorf("transaction died")
	case res := <-tx.Responses():
		return res, nil
	}
}
